-- -------------------------------------------------------------------------
-- Features/main.lua
-- Modular Feature Manager
-- -------------------------------------------------------------------------

local features = {}

-- [Lua 5.4] <const> for function references
local pairs <const> = pairs
local ipairs <const> = ipairs
local pcall <const> = pcall
local tostring <const> = tostring
local type <const> = type
local table_insert <const> = table.insert

-- [Module List]
-- Keys used for internal references, file names correspond to files in ClickUl/Features/
local modules = {
    self = { file = "Self", label = "Self", instance = nil },
    player = { file = "Player", label = "Player", instance = nil },
    online = { file = "Online", label = "Online", instance = nil },
    weapon = { file = "Weapon", label = "Weapon", instance = nil },
    spawn = { file = "Spawn", label = "Spawn", instance = nil },
    vehicle = { file = "Vehicle", label = "Vehicle", instance = nil },
    world = { file = "World", label = "World", instance = nil },
    game = { file = "Game", label = "Game", instance = nil },
    heist = { file = "Heist", label = "Heist", instance = nil },
    setting = { file = "Setting", label = "Setting", instance = nil },
    -- Player info overlay module (no label - not shown in sidebar)
    player_info = { file = "PlayerInfo", label = nil, instance = nil }
}

local modules_array = {}
local modules_count = 0

local on_tick_funcs = {}
local on_tick_count = 0

-- [Lua 5.4] <const> for static display order
local tab_order <const> = { "self", "player", "online", "weapon", "spawn", "vehicle", "world", "game", "heist", "setting"}

-- [Dependencies]
local ui = nil
local config = nil
local natives = nil
local lang = nil
local lexis = nil
local json = nil
local debugger = nil

-- [State]
local player_tab_index = -1 -- Dynamically calculated

local function _T(text)
    if _G and _G._T then
        return _G._T(text)
    end
    if lang then
        if lang.get then return lang.get(text) end
        if lang.get_text then return lang.get_text(text) end
    end
    return text
end

-- [Helpers]
local function log_err(msg)
    if debugger and debugger.error then
        debugger.error("[Features]", tostring(msg))
    end
end

local function init_module(info)
    if type(info) ~= "table" then return end
    if type(info.instance) ~= "table" then return end
    if type(info.instance.init) ~= "function" then return end
    if debugger and debugger.debug then
        pcall(debugger.debug, "Initializing module: " .. tostring(info.file))
    end

    -- Safe Init
    local ok, err = pcall(info.instance.init, ui, config, natives, lang, json, lexis, debugger)
    if not ok then
        log_err("Failed to init module " .. tostring(info.file) .. ": " .. tostring(err))
        if ui and ui.notify then
            pcall(ui.notify, "Init failed: " .. tostring(info.file), "Error")
        end
    end
end

local function broadcast(event_name)
    for i = 1, modules_count do
        local info = modules_array[i]
        local inst = info.instance
        local fn = inst and inst[event_name]
        if fn then
            local ok, err = pcall(fn)
            if not ok then
                log_err("Module " .. tostring(info.file) .. " " .. event_name .. " error: " .. tostring(err))
                if debugger then
                    debugger.error("Module error in " .. info.file, {event = event_name, error = err})
                end
            end
        end
    end
end

local function broadcast_on_tick()
    for i = 1, on_tick_count do
        local entry = on_tick_funcs[i]
        local ok, err = pcall(entry.fn)
        if not ok then
            log_err("Module " .. tostring(entry.file) .. " on_tick error: " .. tostring(err))
        end
    end
end

-- Link player info overlay dependencies
-- Inject Player module instance into PlayerInfo for accessing selected player ID
local function link_overlay()
    if modules.player_info.instance and modules.player.instance then
        if modules.player_info.instance.set_player_list then
            modules.player_info.instance.set_player_list(modules.player.instance)
        end
    end
end

-- -------------------------------------------------------------------------
-- Core API
-- -------------------------------------------------------------------------

function features.init(ui_lib, cfg_lib, nat_lib, lang_lib, json_lib, lexis_lib, debug_lib)
    ui = ui_lib
    config = cfg_lib
    natives = nat_lib
    lang = lang_lib
    lexis = lexis_lib
    json = json_lib
    debugger = debug_lib

    if debugger then debugger.info("Features module initializing") end

    if not (ui and config and natives) then error("Features module missing dependencies") end

    for i, key in ipairs(tab_order) do
        if key == "setting" then
            if ui.set_settings_tab_index then
                ui.set_settings_tab_index(i)
            end
        elseif key == "player" then
            player_tab_index = i -- Store this for draw_overlays
        end
    end

    -- Dynamically load submodules
    local root_path = "ClickUl.Features."

    for _, info in pairs(modules) do
        local path = root_path .. info.file
        local status, mod = pcall(require, path)

        if status and mod then
            info.instance = mod
            init_module(info)
            -- log_err("Module loaded: " .. info.file) -- Optional: reduce spam
        else
            log_err("Failed to load module: " .. info.file .. " | Error: " .. tostring(mod))
            if util and util.toast then util.toast("Error loading module: " .. info.file) end
        end
    end

    modules_count = 0
    for _, info in pairs(modules) do
        modules_count = modules_count + 1
        modules_array[modules_count] = info
    end

    on_tick_count = 0
    for i = 1, modules_count do
        local info = modules_array[i]
        if info.instance and info.instance.on_tick then
            on_tick_count = on_tick_count + 1
            on_tick_funcs[on_tick_count] = { fn = info.instance.on_tick, file = info.file }
        end
    end

    if debugger then
        debugger.info("Modules cached: " .. modules_count .. ", on_tick handlers: " .. on_tick_count)
    end

    -- Link module dependencies
    link_overlay()

    if debugger then
        debugger.info("All feature modules loaded successfully")
        debugger.log_memory("Post-feature-init")
    end
end

function features.on_menu_open()
    broadcast("on_menu_open")
end

function features.on_menu_close()
    broadcast("on_menu_close")
end

function features.on_tick()
    broadcast_on_tick()
end

-- Draw overlay layer
-- Called by Loader after main window is drawn
-- Only shows on Player tab
function features.draw_overlays()
    if player_tab_index == -1 then return end

    local active_tab = ui.get_active_tab()
    if active_tab ~= player_tab_index then return end

    if modules.player_info and modules.player_info.instance and modules.player_info.instance.draw_overlay then
        local status, err = pcall(modules.player_info.instance.draw_overlay)
        if not status then
            log_err("Overlay draw error: " .. tostring(err))
        end
    end
end

function features.draw_menu()
    -- 1. Build sidebar tab list
    local sidebar_tabs = {}
    for _, key in ipairs(tab_order) do
        local label = modules[key].label
        table_insert(sidebar_tabs, _T(label))
    end

    -- 2. Draw sidebar
    ui.Sidebar(sidebar_tabs)

    -- 3. Get currently selected tab index
    local active_idx = ui.get_active_tab()

    -- 4. Find corresponding module and draw content
    local active_key = tab_order[active_idx]
    if active_key then
        local module_info = modules[active_key]
        if module_info and module_info.instance and module_info.instance.draw then
            -- Call submodule's draw function
            local status, err = pcall(module_info.instance.draw)
            if not status then
                -- Log error to debugger (not print to prevent Lexis capture)
                if debugger and debugger.error then
                    debugger.error("[Features]", "Module draw error in " .. module_info.file .. ": " .. tostring(err))
                end
                if util and util.toast then
                    util.toast(_T("Module Error") .. ": " .. module_info.file)
                end
                ui.Group(_T("Module Error"), function()
                    ui.Button(_T("Error") .. ": " .. tostring(err))
                end)
            end
        else
            ui.Group(_T("Empty Module"), function()
                ui.Button(_T("No content available for") .. " " .. (module_info.file or "Unknown"))
            end)
        end
    end
end

return features
